#include "snipmath.h"
#include <math.h>
#include <stdio.h>

#define LOCKED 1
#define FREEEE 0
#define GLOBALOCUPADO 1 
#define N 3

#define ADDR_LOCK 5242880

//VARIAVEIS GLOBAIS TEM ENDEREÇO COMPARTILHADO PELOS CORES
//VARIAVEIS LOCAIS SÂO INDEPENDETES

int  AcquireGlobalLock();
void ReleaseGlobalLock();
int  AcquireLock(int);
void ReleaseLock(int);

int global_locks[N] = {1, 2, 3}; // VETOR DE LOCKS LOCAIS - CADA [] RECEBE O NUMERO DO CORE RESPONSAVEL
int global_proc = 1; // CONTADOR GLOBAL DOS PROCESSADORES, CADA UM RECEBE UM NUMERO UNICO

/* The printf's may be removed to isolate just the math calculations */

int main(void)
{
  int proc;

  double  a1 = 1.0, b1 = -10.5, c1 = 32.0, d1 = -30.0;
  double  a2 = 1.0, b2 = -4.5, c2 = 17.0, d2 = -30.0;
  double  a3 = 1.0, b3 = -3.5, c3 = 22.0, d3 = -31.0;
  double  a4 = 1.0, b4 = -13.7, c4 = 1.0, d4 = -35.0;
  double  x[3];
  double X, testeVAR;
  int     solutions;
  int i;
  unsigned long l = 0x3fed0169L;
  struct int_sqrt q;
  long n = 0;
  FILE *cubic_sol, *rad2grad_sol, *square_sol;

  while(AcquireGlobalLock() != 0);
  proc = global_proc;
  global_proc++;
  ReleaseGlobalLock(); 
  //AcquireLock(proc);

  /* printf ("\nmeu proc eh = %d\n", proc); */
  /* while(AcquireGlobalLock() != 0); */
  /* printf("estado atual do bagulho\n"); */
  /* printf("pos 0 = %d\n", global_locks[0]); */
  /* printf("pos 1 = %d\n", global_locks[1]); */
  /* printf("pos 2 = %d\n", global_locks[2]); */
  /* ReleaseGlobalLock();  */

  if(global_locks[0] == proc){  
    cubic_sol = fopen("cubic_sol.txt", "w");
    /* solve soem cubic functions */
    while(AcquireGlobalLock() != 0);
    printf("********* CUBIC FUNCTIONS ***********\n");
    ReleaseGlobalLock(); 

    /* should get 3 solutions: 2, 6 & 2.5   */
    SolveCubic(a1, b1, c1, d1, &solutions, x);
    fprintf(cubic_sol, "Solutions:");

    while(AcquireGlobalLock() != 0);
    for(i=0;i<solutions;i++)
      fprintf(cubic_sol, " %f",x[i]);
    fprintf(cubic_sol, "\n");
  ReleaseGlobalLock(); 

    /* should get 1 solution: 2.5           */
    SolveCubic(a2, b2, c2, d2, &solutions, x);  
    fprintf(cubic_sol, "Solutions:");

    while(AcquireGlobalLock() != 0);
    for(i=0;i<solutions;i++)
      fprintf(cubic_sol, " %f",x[i]);
    fprintf(cubic_sol, "\n");
  ReleaseGlobalLock(); 

    SolveCubic(a3, b3, c3, d3, &solutions, x);
    fprintf(cubic_sol, "Solutions:");

    while(AcquireGlobalLock() != 0);
    for(i=0;i<solutions;i++)
      fprintf(cubic_sol, " %f",x[i]);
    fprintf(cubic_sol, "\n");
  ReleaseGlobalLock(); 

    SolveCubic(a4, b4, c4, d4, &solutions, x);
    fprintf(cubic_sol, "Solutions:");

    while(AcquireGlobalLock() != 0);
    for(i=0;i<solutions;i++)
      fprintf(cubic_sol, " %f",x[i]);
    fprintf(cubic_sol, "\n");
  ReleaseGlobalLock(); 

    /* Now solve some random equations */
    for(a1=1;a1<10;a1=d1_add(a1, 1.0)) {
      for(b1=10;b1>0;b1--) {
	for(c1=5;c1<15;c1=d1_add(c1, 0.5)) {
	  for(d1=-1;d1>-11;d1--) {
	    SolveCubic(a1, b1, c1, d1, &solutions, x);
	    fprintf(cubic_sol, "Solutions:");

	    while(AcquireGlobalLock() != 0);
	    for(i=0;i<solutions;i++)
	      fprintf(cubic_sol, " %f",x[i]);
	    fprintf(cubic_sol, "\n");
	    ReleaseGlobalLock(); 
	  }
	}
      }
    }
    fflush(cubic_sol);
    fclose(cubic_sol);
  }


  if(global_locks[2] == proc) {
    rad2grad_sol = fopen("rad2grad_sol.txt", "w");
    while(AcquireGlobalLock() != 0);
    printf("********* ANGLE CONVERSION ***********\n");
    ReleaseGlobalLock(); 
    /* convert some rads to degrees */
    while(AcquireGlobalLock() == GLOBALOCUPADO);
    for (X = 0.0; X <= 360.0; X = d2_add(X, 1.0)){
     
      fprintf(rad2grad_sol,"%3.0f degrees = %.12f radians\n", X, deg2rad(X));
   
    }
    ReleaseGlobalLock();
    puts("");
    while(AcquireGlobalLock() == GLOBALOCUPADO);
    for (X = 0.0; X <= (2 * PI + 1e-6); X = d2_add(X, (PI / 180))){

      fprintf(rad2grad_sol,"%.12f radians = %3.0f degrees\n", X, rad2deg(X));
    
    }
    ReleaseGlobalLock();
    fflush(rad2grad_sol);
    fclose(rad2grad_sol);
  }




  if(global_locks[1] == proc){ 
    square_sol = fopen("square_sol.txt", "w");
    while(AcquireGlobalLock() != 0);
    printf("********* INTEGER SQR ROOTS ***********\n");
    ReleaseGlobalLock(); 
    /* perform some integer square roots */
    for (i = 0; i < 1001; ++i)
      {
        usqrt(i, &q);
	// remainder differs on some machines
	// printf("sqrt(%3d) = %2d, remainder = %2d\n",
 while(AcquireGlobalLock() != 0);
	fprintf(square_sol, "sqrt(%3d) = %2d\n",
		i, q.sqrt);
  ReleaseGlobalLock(); 
      }
    usqrt(l, &q);
    //printf("\nsqrt(%lX) = %X, remainder = %X\n", l, q.sqrt, q.frac);
 while(AcquireGlobalLock() != 0);
    fprintf(square_sol, "\nsqrt(%lX) = %X\n", l, q.sqrt);
  ReleaseGlobalLock(); 
    fflush(square_sol);
    fclose(square_sol);
  }






  exit(0);
  return 0;
}

int AcquireGlobalLock() {
  volatile int *lock = (int *) ADDR_LOCK;
  int ret;
  ret = *lock;
  return ret;
}

void ReleaseGlobalLock() {
  volatile int *lock = (int *) ADDR_LOCK;
  *lock = FREEEE;
} 

int AcquireLock(int proc) {
  int i;
  while(AcquireGlobalLock() == GLOBALOCUPADO);
  for(i = 0; i < N; i++){
    if(global_locks[i] == FREEEE){
      global_locks[i] = proc;
      break;
    }
  }
  ReleaseGlobalLock();
}

void ReleaseLock(int lock) {
  global_locks[lock] = FREEEE;
  return;
}

